#include "tcpmgr.h"
#include <QAbstractSocket>
#include "../usermgr.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <qfileinfo.h>
#include "file_upload.pb.h"
#include "file_download.pb.h"


TcpMgr::TcpMgr():_host(""),_port(),_b_recv_pending(false),_message_id(0),_message_len(0)
{
    registerMetaType();
    //连接发送信号用来发送数据
    QObject::connect(this, &TcpMgr::sig_send_data, this, &TcpMgr::slot_send_data);
    QObject::connect(this, &TcpMgr::sig_sendUploadRequest, this, &TcpMgr::slot_sendUploadRequest);
    QObject::connect(this, &TcpMgr::sig_sendDownloadRequest, this, &TcpMgr::slot_sendDownloadRequest);


    //注册消息
    initHandlers();
}

TcpMgr::~TcpMgr(){

}
void TcpMgr::initHandlers()
{
    //auto self = shared_from_this();
    //用户登录资源服务器回包:
    _handlers.insert(ID_RES_LOGIN_RSP, [this](ReqId id, int len, QByteArray data){
        Q_UNUSED(len);
        qDebug()<< "handle id is "<< id ;
        // 将QByteArray转换为QJsonDocument
        QJsonDocument jsonDoc = QJsonDocument::fromJson(data);

        // 检查转换是否成功
        if(jsonDoc.isNull()){
            qDebug() << "Failed to create QJsonDocument.";
            return;
        }

        QJsonObject jsonObj = jsonDoc.object();
        qDebug()<< "data jsonobj is " << jsonObj ;

        if(!jsonObj.contains("error")){
            int err = ErrorCodes::Error_Json;
            qDebug() << "Login Failed, err is Json Parse Err" << err ;
            emit sig_login_failed(err);
            return;
        }

        int err = jsonObj["error"].toInt();
        if(err != ErrorCodes::SUCCESS){
            qDebug() << "Login Failed, err is " << err ;
            emit sig_login_failed(err);
            return;
        }

        //登陆成功！切换页面以及设置用户信息
        auto uid = jsonObj["uid"].toInt();
        auto email = jsonObj["email"].toString();
        auto token = jsonObj["token"].toString();

        UserMgr::GetInstance()->setuid(uid);
        UserMgr::GetInstance()->setemail(email);
        UserMgr::GetInstance()->settoken(token);

        emit sig_swich_mainwindow();
    });
    //用户备份文件回包:
    _handlers.insert(ID_FILE_UPLOAD_RSP, [this](ReqId id, int len, QByteArray data) {
        Q_UNUSED(len);
        qDebug() << "handle id is " << id << " data is " << data;
        file_upload::FileUploadRsp rsp;
        rsp.ParseFromArray(data.data(), len);

        if(rsp.error_code() != 0) {
            qDebug() << "上传失败，错误码：" << rsp.error_code();
            return;
        }

        // 1. 通过file_hash找到对应的FileInfo
        QString fileHash = QString::fromStdString(rsp.file_hash());
        if(!_uploadContext.contains(fileHash)) return;

        FileInfo info = _uploadContext[fileHash];
        info.fileId = rsp.file_id(); // 赋值服务器返回的file_id
        _uploadContext.remove(fileHash);

        // 2. 标记历史记录为已上传
        emit sig_uploadFinished(info); // 通知UI更新HistoryRecordItem状态

        // 3. 同步到备份表（新增BackupRecordItem）
        emit sig_addBackupRecord(info); // 通知UI在backuptable添加项

        return;
    });

    //用户下载文件回包:
    _handlers.insert(ID_FILE_DOWNLOAD_RSP, [this](ReqId id, int len, QByteArray data) {
        Q_UNUSED(len);
        qDebug() << "handle id is " << id << " data is " << data;

        file_download::FileDownloadRsp rsp;
        rsp.ParseFromArray(data.data(), len);

        if(rsp.error_code() != 0) {
            qDebug() << "下载失败，错误码：" << rsp.error_code()
                << "，文件ID：" << rsp.file_id();
            return;
        }

        // 1. 通过file_id找到对应的下载上下文
        if(!_downloadContext.contains(rsp.file_id())) {
            qDebug() << "未找到文件ID对应的下载上下文：" << rsp.file_id();
            return;
        }

        // 2. 从配置文件获取保存路径
        QString saveDir = "";/*ConfigMgr::GetInstance()->getDownloadPath();
        if(!QDir(saveDir).exists()) QDir().mkpath(saveDir);*/

        // 3. 生成保存路径（配置路径 + 文件名）
        QString fileName = QString::fromUtf8(
            rsp.logical_name().data(),
            rsp.logical_name().size()
            );
        QString savePath = QString("%1/%2").arg(saveDir, fileName);

        // 4. 写入文件
        QFile file(savePath);
        if(file.open(QIODevice::WriteOnly)) {
            file.write(rsp.file_data().data(), rsp.file_data().size());
            file.close();
            qDebug() << "文件保存成功：" << savePath
                     << "，文件ID：" << rsp.file_id();

            // 5. 通知UI更新对应BackupRecordItem的状态
            emit sig_downloadFinished(rsp.file_id());

            // 6. 清理上下文
            _downloadContext.remove(rsp.file_id());
        }
        return;
    });
}

void TcpMgr::handleMsg(ReqId id, int len, QByteArray data)
{
    auto find_iter = _handlers.find(id);
    if(find_iter == _handlers.end()){
        qDebug()<< "not found id ["<< id << "] to handle";
        return ;
    }

    find_iter.value()(id,len,data);
}

void TcpMgr::registerMetaType()
{
    qRegisterMetaType<ServerInfo>("ServerInfo");
    qRegisterMetaType<FileInfo>("FileInfo");
    qRegisterMetaType<ReqId>("ReqId");
}

void TcpMgr::initSocket()
{
    _socket = new QTcpSocket(this); // 父对象为this（TcpMgr），确保线程一致
    // 在这里连接_socket的所有信号（原构造函数中的连接移到此处）
    connect(_socket, &QTcpSocket::connected, [&]() {
        qDebug() << "Connected to server!";
        emit sig_con_success(true);
    });
    QObject::connect(_socket, &QTcpSocket::readyRead, [&]() {
        // 当有数据可读时，读取所有数据
        // 读取所有数据并追加到缓冲区
        _buffer.append(_socket->readAll());

        QDataStream stream(&_buffer, QIODevice::ReadOnly);
        stream.setVersion(QDataStream::Qt_5_0);

        forever {
            //先解析头部
            if(!_b_recv_pending){
                // 检查缓冲区中的数据是否足够解析出一个消息头（消息ID + 消息长度）
                if (_buffer.size() < static_cast<int>(sizeof(quint16) * 2)) {
                    return; // 数据不够，等待更多数据
                }

                // 预读取消息ID和消息长度，但不从缓冲区中移除
                stream >> _message_id >> _message_len;

                //将buffer 中的前四个字节移除
                _buffer = _buffer.mid(sizeof(quint16) * 2);

                // 输出读取的数据
                qDebug() << "Message ID:" << _message_id << ", Length:" << _message_len;

            }

            //buffer剩余长读是否满足消息体长度，不满足则退出继续等待接受
            if(_buffer.size() < _message_len){
                _b_recv_pending = true;
                return;
            }

            _b_recv_pending = false;
            // 读取消息体
            QByteArray messageBody = _buffer.mid(0, _message_len);
            qDebug() << "receive body msg is " << messageBody ;

            _buffer = _buffer.mid(_message_len);
            handleMsg(ReqId(_message_id),_message_len, messageBody);
        }

    });

    //5.15 之后版本
    QObject::connect(_socket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::errorOccurred), [&](QAbstractSocket::SocketError socketError) {
        Q_UNUSED(socketError)
        qDebug() << "TCP Error:" << _socket->errorString();
    });

    // 处理连接断开
    QObject::connect(_socket, &QTcpSocket::disconnected, [&]() {
        qDebug() << "Disconnected from server.";
    });

    QObject::connect(_socket, &QTcpSocket::bytesWritten, this, [this](qint64 bytes) {
        //更新发送数据
        _bytes_sent += bytes;
        //未发送完整
        if (_bytes_sent < _current_block.size()) {
            //继续发送
            auto data_to_send = _current_block.mid(_bytes_sent);
            _socket->write(data_to_send);
            return;
        }

        //发送完全，则查看队列是否为空
        if (_send_queue.empty()) {
            //队列为空，说明已经将所有数据发送完成，将pending设置为false，这样后续要发送数据时可以继续发送
            _current_block.clear();
            _pending = false;
            _bytes_sent = 0;
            return;
        }

        //队列不为空，则取出队首元素
        _current_block = _send_queue.front();
        _send_queue.pop();
        _bytes_sent = 0;
        _pending = true;
        qint64 w2 = _socket->write(_current_block);
        qDebug() << "[TcpMgr] Dequeued and write() returned" << w2;
    });
}

void TcpMgr::slot_tcp_connect(ServerInfo si)
{
    qDebug()<< "receive tcp connect signal";
    // 尝试连接到服务器
    qDebug() << "Connecting to server...";
    _host = si.Host;
    _port = static_cast<uint16_t>(si.Port.toUInt());
    _socket->connectToHost(si.Host, _port);
}

void TcpMgr::slot_send_data(ReqId reqId, QByteArray dataBytes)
{
    qDebug()<<"receive sig_send_data";
    uint16_t id = reqId;

    // 计算长度（使用网络字节序转换）
    quint16 len = static_cast<quint16>(dataBytes.length());

    // 创建一个QByteArray用于存储要发送的所有数据
    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);

    // 设置数据流使用网络字节序
    out.setByteOrder(QDataStream::BigEndian);

    // 写入ID和长度
    out << id << len;

    // 添加字符串数据
    block.append(dataBytes);

    //判断是否正在发送
    if (_pending) {
        //放入队列直接返回，因为目前有数据正在发送
        qDebug()<<"放入队列直接返回，因为目前有数据正在发送";
        _send_queue.push(block);
        return;
    }

    // 没有正在发送，把这包设为“当前块”，重置计数，并写出去
    _current_block = block; // ← 保存当前正在发送的 block
    _bytes_sent = 0; // ← 归零
    _pending = true; // ← 标记正在发送

    // 发送数据
    qint64 written = _socket->write(_current_block);
    qDebug() << "tcp mgr send byte data is" << _current_block
             << ", write() returned" << written;
}

void TcpMgr::slot_sendUploadRequest(const QByteArray &data, const FileInfo &info)
{
    _uploadContext[info.fileHash] = info; // 用file_hash关联
    slot_send_data(ID_FILE_UPLOAD_REQ, data);
}

void TcpMgr::slot_sendDownloadRequest(const QByteArray &data, const FileInfo &info)
{
    _downloadContext[info.fileId] = info; // 用file_id关联
    slot_send_data(ID_FILE_DOWNLOAD_REQ, data);
}

TcpThread::TcpThread()
{
    _tcp_thread = new QThread();
    TcpMgr::GetInstance()->moveToThread(_tcp_thread);
    // QObject::connect(_tcp_thread, &QThread::finished, _tcp_thread, &QObject::deleteLater);

    // _tcp_thread->start();
    // 连接线程启动信号到initSocket，确保_socket在新线程中创建
    QObject::connect(_tcp_thread, &QThread::started, TcpMgr::GetInstance().get(), &TcpMgr::initSocket);
    QObject::connect(_tcp_thread, &QThread::finished, _tcp_thread, &QObject::deleteLater);
    _tcp_thread->start();
}

TcpThread::~TcpThread()
{
	if (_socket) {
        _socket->disconnectFromHost();
        _socket->deleteLater(); // 安全删除
    }
    _tcp_thread->quit();
}
